타입 스크립트에는 아래의 기본 타입들이 있다.
튜플은 요소의 쌍을 표현한다. 배열 형태에 타입을 넣어 표현하며 각 요소의 타입은 다를 수 있다.
정해진 index 외에 참조시 오류가 발생한다.
let a: [string, number]
let b: [string, number, any]
...
b[3] // error
열거형은 값의 집합에 이름을 붙혀 표현한 것 이다.
각 값들은 0으로 시작하며 특정 값으로 매기거나 문자열로 설정할 수 도 있다.
enum Color {Red, Blue, Green} // Red: 0, Blue:1, Green: 2
const color: Color = Color.Green
enum Country {KR = 3, US, UK, ANY = KR | US | UK}
enum Alphabet {A = "A", B = "B", C = "C"}
enum Anser = {No = 0, Yes = "YES"} // 가능하지만 두 타입을 섞는 것은 권장하지 않는다.
enum은 숫자형 열거형에 한하여 역 매핑을 지원한다.
enum Enum {
A, B
}
const a = Enum.A
const nameOfA = Enum[a] // "A"
const
를 통해 열거형을 선언하고, 상수 열거형 인 경우 컴파일 타임에서 완전히 제거되고 값은 인라인 된다.
const enum Alpha = {
A = 1,
// ...
}
console.log(Alpha.A)
/*
컴파일 이후 소스
console.log(1)
*/
뭐든지 올 수 있는 타입에 대해서 any를 붙이며 기존의 JS 처럼 타입 타입 검사를 하지 않아야 할 때 유용하다.
타입을 일부만 알거나 타입이 섞인 경우에도 사용할 수 있다.
const list: any[] = [1, "2", true]
any의 반대로 아무것도 없음을 뜻한다. 기본적으로 undefined
나 조건부로 null
만 할당할 수 있다.
항상 오류를 발생시키거나 끝나지 않는 함수를 표현할 때 사용한다.
function error(message: string): never{
throw new Error(message)
}
function infinite(): never{
while(true){
}
}
컴파일 수준에서 특정 타입이라고 컴파일러에게 알리는 역할을 한다. 실제로 런타임에는 영향이 없다.
// 방법 1
const rawValue: any = "this is message"
const messageCount: number = (<string>rawValue).length
// 방법 2 * TSX 사용 시 이 방법만 사용 가능하다.
const rawValue: any = "this is message"
const messageCount: number = (rawValue as string).length
한 가지의 타입에서 여러 타입을 선택적으로 기대하는 경우 유니언 타입을 사용할 수 있다.
type NullableString = string | null;
type StringOrNumber = string | number;
두 타입이나 인터페이스에서 공통의 타입을 가지고 이를 유니언 타입으로 묶으면 공통된 타입은 접근이 가능하다.
interface Bird {
fly(): void;
layEggs(): void;
}
interface Fish {
swim(): void;
layEggs(): void;
}
declare function getSmallPet(): Fish | Bird;
let pet = getSmallPet();
pet.layEggs();
(pet as Fish).swim()
리터럴을 갖는 단일 필드를 이용하여 유니언을 구별할 수 있다.
type NetworkLoadingState = {
state: "loading"; // 리터럴
}
type NetworkFailedState = {
state: "failed";
code: number;
}
type NetworkState = NetworkLoadingState | NetworkFailedState
// NetworkState.state에 따라 유니언을 구별할 수 있다.
유니언과 다르게 두 타입의 값을 모두 포함해야 하는 경우 교차 타입을 통해 묶을 수 있다.
interface ErrorHandling {
success: boolean;
error?: { message: string };
}
interface ArtworksData {
artworks: { title: string }[];
}
interface ArtistsData {
artists: { name: string }[];
}
// 이 인터페이스들은
// 하나의 에러 핸들링과 자체 데이터로 구성됩니다.
type ArtworksResponse = ArtworksData & ErrorHandling;
type ArtistsResponse = ArtistsData & ErrorHandling;
인터페이스는 타입의 이름을 정하고 자신의 코드나 프로젝트 외부에서 사용하는 코드와 계약할 수 있게 도와준다.
?
를 사용하여 선택적 프로퍼티를 정의할 수 있고, readonly
를 이용해 최초 할당 이후 오직 읽기만 가능한 타입을 만들 수 있다.
interface Point {
x: number;
y: number;
}
interface Device{
readonly mac: string; // readonly
name: string;
type?: string; // optional
}
const
와 readonly
변수에 사용되는 경우 const
, 프로퍼티로 사용되는 경우 readonly
를 사용한다.
인터페이스는 함수의 구조도 정의할 수 있다.
이 때 함수에서 받는 파라미터의 이름은 같지 않아도 된다.
interface AddFunc {
(left: number, right: number): number;
}
let add: AddFunc;
add = function(left: number, right:number): number {
return left + right
}
특정 프로퍼티 이외에 여러 프로퍼티를 받으려면 [propName: type]
형태로 받아 처리할 수 있다.
인덱스 서명에는 number
와 string
두 가지의 타입만 지원한다.
단, 숫자형은 실제로 문자형으로 변환되어 적용되므로, 문자형의 하위 호환이어야 한다.
ex) 100 과 “100”은 같은 값으로 처리됨
interface StringArray {
length: number; // 배열의 길이를 나타내는 프로퍼티
[index: number]: string; // 숫자 인덱스를 받아 문자열을 리턴하는 타입
}
interface AnyType {
[key: string]: any; // 아무 문자열을 키로 받아서 any라는 타입을 가진다.
}
// 단 문자열 시그니처를 사용시 반환 타입 (현재 any)이 모두 일치해야 한다.
interface SomeType {
[key: string]: string;
name: string;
length: number; // 오류, 시그니처의 리턴타입이 string이므로, string만 가능하다.
}
인터페이스에서는 extends를 이용해 확장이 가능하다.
이 때 ,
를 이용해 여러 인터페이스를 확장하는 것도 가능하다.
interface Shape {
color: string
}
interface Square extends Shape {
sideLength: number
// color: string 이 상속됨
}
interface PenStroke {
penWidth: number
}
interface RoundPenStroke extends PenStroke, Shape {
radius: number;
// penWidth: number
// color: string
}
인터페이스는 다양한 JS의 타입을 지원하므로, 함수와 프로퍼티를 다 가지고 있는 타입도 사용 가능하다.
interface Counter {
(start: number): string;
interval: number;
reset(): void
}
function getCounter(): Counter {
let counter = (function (start: number) { }) as Counter;
counter.interval = 123;
counter.reset = function () { };
return counter;
}
인터페이스가 클래스의 타입을 확장하면 멤버는 상속되지만 구현은 상속되지 않는다.
class Control {
private state: any;
}
interface SelectableControl extends Control {
select(): void
}
class Button extends Control implements SelectableControl {
select() { }
}
함수의 타입은 아래와 같이 선언한다.
function add(x: number, y: number): number {
return x + y;
}
const subtract: (x: number, y: number) => number = (x: number, y: number) => x - y
함수 타입이나 리턴 값에 따라 타입을 추론한다.
function add(x: number, y: number) { // :number 가 없지만 리턴 타입이 number로 추론됨
return x + y;
}
const subtract: (x: number, y: number) =>
number = (x, y) => x - y // x, y의 타입이 없지만 타입에 따라 number로 추론됨
인터페이스와 동일하게 파라미터에 ?
를 붙여 선택적 매개변수를 표현할 수 있다.
또한 =
를 이용해 기본 값을 지정하여 기본 매개변수를 표현할 수 있다.
단 선택적 매개변수에 한해서 항상 일반 매개변수보다 에 와야 한다.
function log(message: string, stamp?: number){ // (stamp?: number, message: string)은 허용되지 않음
// stamp의 타입은 number | undefined
}
function log(message: string, stamp = new Date().getTime()){
// stamp의 타입은 number
}
this
...
을 이용하여 나머지 매개변수를 받을 수 있고, this
를 이용하여 그 순간에 this
에 할당되는 타입을 지정할 수 있다.
function push(array: number[], ...items: number[]): void {
// array 뒤에 오는 숫자 파라미터의 연속을 items 변수로 받는다.
}
interface Card{
card: number;
}
interface Deck {
numbers: number[]
createCardPicker(this: Deck): () => Card;
}
const deck: Deck = {
numbers: [1,2,3,4],
createCardPicker: function(this: Deck){
// 여기서의 this는 Deck 타입임
const index = Math.floor(Math.random() * this.numbers.length)
return () => {
{
card: this.numbers[index]
}
}
}
}
동일한 함수를 여러번 선언하여 다중 함수 타입을 제공할 수 있다.
function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; };
function pickCard(x): any {
// 인자가 배열 또는 객체인지 확인
// 만약 그렇다면, deck이 주어지고 card를 선택합니다.
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
return pickedCard;
}
// 그렇지 않다면 그냥 card를 선택합니다.
else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
변수 선언 시 let
으로 선언되면 변경 가능성을 알리지만 const
는 변경 되지 않음을 알린다.
const hello = "Hello" // "Hello" 자체로 타입
let world = "World" // "World"는 변할 수 있으므로 string 타입
type Easing = "ease-in" | "ease-out" | "ease-in-out"; // 문자형 리터럴
type Speed = 0.5 | 1 | 1.5 | 2; // 숫자형 리터럴
제네릭을 이용하면 타입에 사용될 타입을 <>
를 통해 받을 수 있다.
인터페이스나 클래스, 함수에서도 사용할 수 있다.
,
를 통해 여러 타입을 받을 수 있다.
type Nullable<T> = T | null // Nullable<string>은 string과 null의 유니온 타입
interface SomeInterface<T>{
value: T
}
function someFunc<T>(arg: T): T {
return T
}
class SomeClass<T, K> {
fieldT: T
fieldK: K
}